package com.tbit.uqbike.push.aop;

import com.tbit.common.utils.TraceUtil;

import com.tbit.uqbike.push.exception.BaseException;
import com.tbit.uqbike.push.pojo.dto.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.servlet.support.RequestContext;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * @Author: chen
 * @Description: 全局异常处理
 * @Date: 创建于 13:38 2021/2/25
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler extends DefaultHandlerExceptionResolver {


    /**
     * 自定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BaseException.class})
    @ResponseBody
    public JsonResult handleBaseException(HttpServletRequest request, BaseException e) {
        log.error("基础异常",e);
        String msg = e.getMessage();
        String traceId = TraceUtil.getTraceIdByLocal();
        if (msg != null && msg.contains("%")) {
            String[] array = msg.split("%");
            RequestContext requestContext = new RequestContext(request);
            String message = requestContext.getMessage(array[1]);
            return JsonResult.fail(message,traceId);
        } else {
            return JsonResult.fail(e.getMessage(),traceId);
        }

    }

    @ExceptionHandler(value = {BindException.class})
    @ResponseBody
    public JsonResult handlerBindException(BindException e) {
        log.error("绑定异常",e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        assert fieldError != null;
        return JsonResult.fail(fieldError.getDefaultMessage(), TraceUtil.getTraceIdByLocal());
    }

    /**
     * http 请求类型
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public JsonResult handlerHttpRequestMethodNotSupportedException(
            HttpRequestMethodNotSupportedException e) {
        log.error("不支持的http请求类型异常",e);
        return JsonResult.fail("不支持的http请求类型", TraceUtil.getTraceIdByLocal());
    }

    /**
     * 处理其他异常，记录到日志
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {Exception.class})
    @ResponseBody
    public JsonResult handerOtherException(Exception e) {
        log.error("服务器异常",e);
        return JsonResult.fail("系统错误", TraceUtil.getTraceIdByLocal());
    }

    @ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
    @ResponseBody
    public JsonResult handerTypeMismatchException(HttpServletRequest request,
                                                  HttpServletResponse response, Object handler, MethodArgumentTypeMismatchException e) {
        log.error("方法参数不匹配异常",e);
        String errmsg = "参数转换失败，方法：" + Objects.requireNonNull(e.getParameter().getMethod()).getName()
                + ",期望参数类型：" + e.getParameter().getParameterType()
                + ",参数：" + e.getParameter()
                + ",信息：" + e.getMessage();
        String url = request.getRequestURI();
        log.error(errmsg + ",接口地址" + url);
        return JsonResult.fail("错误的参数类型", TraceUtil.getTraceIdByLocal());
    }

    @ExceptionHandler(value = {NumberFormatException.class})
    @ResponseBody
    public JsonResult handerNumberFormatException(HttpServletRequest request,
                                                  HttpServletResponse response, Object handler, NumberFormatException e) {
        log.error("数字转换异常",e);
        return JsonResult.fail("错误的参数类型", TraceUtil.getTraceIdByLocal());
    }

}
